<template>
	<!-- 百分比的额尺寸模式时用到的参考标准 -->
	<div v-if="loading === -1" id="div" style="width: 100%;height: 100%;"/>
	<!-- 图片正常显示 -->
	<div v-else-if="loading === 0" :style="[{position: 'relative', overflow}, getSizeStyle(realInfo)]">
		<!-- 显示轮播图 -->
		<swiper v-if="srcList" :style="[getSizeStyle(realInfo, false)]" :autoplay="bannerInfo.autoplay" :interval="bannerInfo.interval" :duration="bannerInfo.duration" @change="e => bannerInfo.current = e.detail.current">
			<swiper-item v-for="(src, index) in srcList" :key="index">
				<image class="image" :src="src" :mode="iMode" :style="[getSizeStyle(realInfo), {...iStyle}]" @click="onBanner(index)"/>
			</swiper-item>
		</swiper>
		<block v-else>
			<!-- 显示一张图 绘制好后的图 -->
			<image v-if="showImage || tempFilePath" class="image" :src="tempFilePath || iPath" :mode="iMode" :style="[getSizeStyle(realInfo), {...iStyle}]" :onClick="`event.cancelBubble = ${showBig || cancelBubble}`" @click="click"/>
			<!-- 绘图组件 -->
			<CaCanvas v-if="showCanvas" id="canvas" :width="realInfo.width" :height="realInfo.height" :drawAction="drawAction" hideCanvasing showImage @success="drawSuccess"/>
			<!-- 绘制完成之后的逐块显示 -->
			<div v-if="intact.show" class="center-column" style="position: relative;z-index: 1;">
				<div v-for="(child, index) in material" :key="index" style="display: flex;">
					<div v-for="(item, idx) in child" :key="idx">
						<div v-if="item.src" :style="[{
							position: 'relative', display: 'flex',
							width: (idx === 1 ? centerInfo.width : (item.frame.width * wScale)) + 'px', 
							height: (index === 1 ? centerInfo.height : (item.frame.height * hScale)) + 'px',
						}, (idx === 1 || index === 1) && 0 ? {
							backgroundColor: `rgba(${index * 80}, ${idx * 80}, ${index * idx * 25}, 1)`,
							backgroundImage: `url(${item.src})`,
							backgroundSize: 'contain',
							backgroundPosition: item.position,
							backgroundRepeat: getRepeat(index, idx),
						} : {}, reviseStyle(item.position)]">
							<!-- 使用背景图不能完全填满，是故采用手动平铺来完成 -->
							<div :style="[{position: 'absolute', left: 0, top: 0, zIndex: -1, overflow: 'hidden', width: '100%', height: '100%'}, {display: 'flex', flexWrap: 'wrap'}]">
								<image v-for="i in imageCount(index, idx, item)" :key="i" :src="item.src" :style="[{
									width: item.frame.width * wScale + 'px', height: item.frame.height * hScale + 'px'
								}]" mode="scaleToFill"></image>
							</div>
							<div v-if="item.key === 'center'" id="center" ref="center" :style="[{padding: getContentPadding(), width: 'auto', height: 'auto', zIndex: 1}]">
								<slot name="center" :info="{width: item.frame.width * wScale, height: item.frame.height * hScale, wScale, hScale, refresh: refreshSize}"></slot>
							</div>
							<div v-else-if="item.key === 'right-bottom'" :style="[{width: item.frame.width * wScale + 'px', height: item.frame.height * hScale + 'px', zIndex: 1}]">
								<slot name="right-bottom" :info="{width: item.frame.width * wScale, height: item.frame.height * hScale, wScale, hScale}"></slot>
							</div>
							<!-- 微信小程序不支持动态命名下传值。如需传值仿照right-bottom的写法 -->
							<div v-else :style="[{width: item.frame.width * wScale + 'px', height: item.frame.height * hScale + 'px', zIndex: 1}]">
								<slot :name="item.key"></slot>
							</div>
						</div>
					</div>
				</div>
			</div>
		</block>
		<!-- 图片中间插槽 -->
		<div v-if="hasCenter" style="position: absolute;top: 0;left: 0;bottom: 0;right: 0">
			<slot :info="{...realInfo, wScale, hScale}"></slot>
		</div>
	</div>
	<!-- 正在加载中和加载失败 -->
	<div v-else-if="loading > 0" class="center" :style="[{position: 'relative'}, getSizeStyle(sourceInfo)]">
		<IconFont type="image" :size="sourceInfo.size"/>
		<div class="center" style="position: absolute;width: 100%;height: 100%;">
			<!-- <image :src="imagetool.StaticObj[loading === 1 ? 'loading' : 'loadnoau']()" style="height: 20px" mode="aspectFit"></image> -->
		</div>
	</div>
</template>

<script>

	import base from '@/components/index.vue'
	
	// 图片保护性拉伸下margin的修正值。经测试，该值为1完美，为0时总有间隙
	const revise = 1
	
	/**
	 * 外面必然包裹一层div，
	 * 一开始有一个默认的宽高，
	 * 等图片信息完全后，会根据图片的实际宽高重新安排div的宽高，并且执行success事件告诉父组件该内容的宽高 - 未测试通过
	 * 
	 * 插槽：
	 * 默认default：需hasCenter支持
	 * 保护性拉伸的情况下有上左下右彼此组合以及center共九个
	 * left-top、right-top、left-bottom、right-bottom：左上、右上、左下、右下
	 * left、center、right：中间行的左中右
	 * top、center、right：中间列的上中下
	 */
	
	export default {
		extends: base,
		/**
		 * success：图片初始化成功，回调参数是真实的尺寸和缩放比例
		 * newImage：新图绘制成功(包含截图的情况)。回调参数是新图路径
		 * center：保护性拉伸时，最中间图片的绘制结果。回调参数是material[1][1]
		 * click：该图的点击事件
		 */
		emits: ['success', 'newImage', 'center', 'click'],
		props: {
			/**
			 * String类型，默认是url。也可以是相对路径。不用传require(path)
			 * Array类型，可以轮播，也可以限定只显示一张
			 * 也可以是base64。比如读取本都图片在微信小程序下就是base64的格式，微信小程序不能直接读取，需转换为临时路径才可以
			 */
			src: {
				type: [String, Array]
			},
			// 轮播设置。需src是数组支持
			bannerInfo: {
				type: Object,
				default: () => {
					return {
						current: 0, // 当前轮播第一个
						autoplay: true, // 是否自动轮播
						interval: 5000, // 间隔时间
						duration: 1000, // 动画时间
					}
				}
			},
			/**
			 * 图片显示模式
			 * 
			 * scaleToFill 默认值 不保持纵横比缩放图片，使图片的宽高完全拉伸至填满 image 元素。
			 * aspectFit 保持纵横比缩放图片，使图片的长边能完全显示出来。也就是说，可以完整地将图片显示出来。
			 * aspectFill 保持纵横比缩放图片，只保证图片的短边能完全显示出来。也就是说，图片通常只在水平或垂直方向是完整的，另一个方向将会发生截取。
			 * widthFix 宽度不变，高度自动变化，保持原图宽高比不变
			 * heightFix 高度不变，宽度自动变化，保持原图宽高比不变
			 * top 不缩放图片，只显示图片的顶部区域
			 * bottom 不缩放图片，只显示图片的底部区域
			 * center 不缩放图片，只显示图片的中间区域
			 * left 不缩放图片，只显示图片的左边区域
			 * right 不缩放图片，只显示图片的右边区域
			 * top left 不缩放图片，只显示图片的左上边区域
			 * top right 不缩放图片，只显示图片的右上边区域
			 * bottom left 不缩放图片，只显示图片的左下边区域
			 * bottom right 不缩放图片，只显示图片的右下边区域
			 */
			mode: String,
			// 可以是数值，默认单位px。也可以带单位，支持的单位有px、upx、vw、vh、%
			width: [String, Number],
			height: [String, Number],
			// 宽高相同的尺寸，这种模式下mode被修正为aspectFit。同上
			size: [String, Number],
			// 最大的宽高度。如果小于10，表示高/宽度的多少倍；如果大于10，表示真实的宽/高度。同上
			maxWidth: [String, Number],
			maxHeight: [String, Number],
			// 圆角。-1表示高度的一半；大于0表示对应的圆角。其余同上
			radius: [String, Number],
			// 自定义样式
			iStyle: Object,
			// 是否点击预览全图。如果是，则不再响应其它的点击事件
			showBig: Boolean,
			// 显示所有大图的信息。不传则显示单张大图。
			bigInfo: Object,
			// 是否阻断事件
			cancelBubble: Boolean,
			// 是否有中间内容。如果有点击事件将交给中间内容来控制
			hasCenter: Boolean,
			
			/**
			 * 以下四种情况都需要绘图支持
			 */
			
			// 是否要得到新的图片。只是单纯的绘制一张新图
			newImage: Boolean,
			/**
			 * 该frame存在，表示要截图显示。截图显示最终以该frame的宽高为基准
			 * 需要截图的部分。分别是相对于原图的数据
			 * 支持数值或者百分数。其它不支持
			 *  x: 0,
				y: 0,
				width: 0,
				height: 0
			 */
			frame: Object,
			/**
			 * 是否需要替换图片中的颜色
			 * 第一个是图片中的原始颜色值，支持数组，表示多个颜色值要替换
			 * 第二个是要替换的颜色值。与第一个值一一对应
			 */
			colors: Array,
			/**
			 * 是否需要保护图片以拉伸
			 * 保护区域 - 数值都是相对于原始图片来说的
			 * 如果是对象，则有top、right、bottom、right四个保护边距
			 * 如果是数值或者字符串，表示四条边值都相同
			 * 最多等于宽高的一半
			 * 
			 * 支持数值或者百分数。其它不支持
			 * 比如：20%。表示top、right、bottom、right值为原图数据的20%
			 */
			side: [String, Number, Object],
			/**
			 * 为了让四条边能够完美的渲染平铺，需监听内部元素变化
			 * 可以监听到offsetLeft(marginLeft)和offsetTop(marginTop)，确无法监听到marginBottom和marginRight
			 * 所以如果有marginBottom和marginRight，需指定传入
			 * top和left如果有值，以其值为准，没有值，以默认获取的为准
			 * 同时可指定width和height，让小程序等不适配refs以获取宽高
			 */
			observeSize: {
				type: Object,
				default: () => {
					return {
						top: 0,
						left: 0,
						bottom: 0,
						right: 0,
						
						width: 0, height: 0
					}
				}
			},
			/**
			 * 溢出设置
			 * visible：内容不能被裁减并且可能渲染到边距盒（padding）的外部
			 * hidden：如果需要，内容将被裁减以适应边距（padding）盒。不提供滚动条，也不支持允许用户滚动（例如通过拖拽或者使用滚轮）。内容可以以编程的方式滚动（例如，通过设置 scrollLeft 等属性的值或 scrollTo() 方法）, 因此该元素仍然是一个滚动的容器。
			 * clip：类似于 hidden，内容将以元素的边距（padding）盒进行裁剪。clip 和 hidden 之间的区别是 clip 关键字禁止所有滚动，包括以编程方式的滚动。该盒子不是一个滚动的容器，并且不会启动新的格式化上下文。如果你希望开启一个新的格式化上下文，你可以使用 display: flow-root 来这样做。
			 * scroll：如果需要，内容将被裁减以适应边距（padding）盒。无论是否实际裁剪了任何内容，浏览器总是显示滚动条，以防止滚动条在内容改变时出现或者消失。打印机可能会打印溢出的内容。
			 * auto：取决于用户代理。如果内容适应边距（padding）盒，它看起来与 visible 相同，但是仍然建立了一个新的块级格式化上下文。如果内容溢出，则浏览器提供滚动条。
			 * overlay：行为与 auto 相同，但是滚动条绘制在内容之上，而不是占据空间。
			 */
			overflow: {
				type: String,
				default: 'hidden'
			}
		},
		watch: {
			src(value) {
				this.initial()
			},
			width(value) {
				this.initial()
			},
			height(value) {
				this.initial()
			},
			size(value) {
				this.initial()
			},
			maxWidth(value) {
				this.initial()
			},
			maxHeight(value) {
				this.initial()
			},
			radius(value) {
				this.initial()
			}
		},
		data() {
			return {
				/**
				 * 图片加载状态
				 * -2：完全不显示
				 * -1：初始状态，还未开始加载
				 * 0：正常加载。这个状态才显示图片
				 * 1：正在加载中
				 * 2：加载失败
				 */
				loading: -1,
				// loading === -1时div的尺寸信息，作为父组件的宽高标准
				parentInfo: undefined,
				
				iPath: '', // 第一张图片，字符串。该组件的信息依据该字段
				srcList: undefined, // 所有图片，数组，存在表示要轮播，并且不显示绘制相关的内容
				iMode: this.mode || 'aspectFit',
				showImage: false, // 一张图片的情况下，显示该图
				
				sourceInfo: {width: 180, height: 80, size: 80}, // 初始宽高。默认比例是1:1
				borderRadius: 0, // 实际圆角值
				realInfo: undefined, // 实际宽高
				wScale: 1, // 实际宽与原图宽的比
				hScale: 1, // 实际高与原图高的比
				// 绘制出图片的路径
				tempFilePath: '',
				// 是否开始绘图
				showCanvas: false,
				
				// 保护区域
				intact: {
					show: false, // 是否可以显示了
					count: 0, // 绘图完成的计数器
					top: 0, right: 0, bottom: 0, left: 0
				},
				// 图片拉伸的中间部分的宽高。是实际的宽高，非相对于图片的宽高
				centerInfo: {
					width: 0, height: 0
				},
				// 图片拉伸显示的九部分内容。xywh都是相对于原图的数值
				material: [
					[ // 第一行
						{ // 左上角
							key: 'left-top', data: [],
							src: '', position: 'bottom right',
							frame: {x: 0, y: 0, width: 0, height: 0},
						},
						{ // 上边
							key: 'top', data: [],
							src: '', position: 'bottom',
							frame: {x: 0, y: 0, width: 0, height: 0}
						},
						{ // 右上角
							key: 'right-top', data: [],
							src: '', position: 'bottom left',
							frame: {x: 0, y: 0, width: 0, height: 0}
						}
					],
					[ // 第二行
						{ // 左边
							key: 'left', data: [],
							src: '', position: 'right',
							frame: {x: 0, y: 0, width: 0, height: 0}
						},
						{ // 中心
							key: 'center', data: [],
							src: '', position: 'center',
							frame: {x: 0, y: 0, width: 0, height: 0}
						},
						{ // 右边
							key: 'right', data: [],
							src: '', position: 'left',
							frame: {x: 0, y: 0, width: 0, height: 0}
						}
					],
					[ // 第三行
						{ // 左下角
							key: 'left-bottom', data: [],
							src: '', position: 'top right',
							frame: {x: 0, y: 0, width: 0, height: 0}
						},
						{ // 下边
							key: 'bottom', data: [],
							src: '', position: 'top',
							frame: {x: 0, y: 0, width: 0, height: 0}
						},
						{ // 右下角
							key: 'right-bottom', data: [],
							src: '', position: 'top left',
							frame: {x: 0, y: 0, width: 0, height: 0}
						}
					]
				],
			}
		},
		computed: {
			minValue() {
				return this.core.common.minValue
			},
			initialSize() {
				return this.core.common.initialSize
			}
		},
		mounted() {
			const action = () => {
				this.core.component.query('#div', this).then(this.initial)
			}
			// #ifdef MP-WEIXIN
			// 小程序仍然可能获取不到真实的宽度
			this.core.delayAction(action, 300)
			// #endif
			// #ifndef MP-WEIXIN
			this.$nextTick(action)
			// #endif
		},
		methods: {
			/**
			 * 1，根据传入的值来确定初始宽高
			 * 2，获取图片信息，拿到真实的宽高数值
			 */
			initial(parentInfo = this.parentInfo) {
				if (parentInfo) {
					this.parentInfo = parentInfo
					// 默认的宽高比例是9:4
					const scale = 9 / 4
					var {src, bannerInfo, imageSuccess} = this
					if (src && src.length > 0) {
						// 1，根据传入的值来确定初始宽高
						const sourceInfo = {}
						const arr = ['width', 'height', 'size', 'maxWidth', 'maxHeight', 'radius']
						arr.forEach(key => {
							var last = key.substr(-3)
							var type = last === 'dth' ? 'width' : last === 'ght' ? 'height' : 'size'
							sourceInfo[key] = this.initialSize(this[key], type, '#div', parentInfo[type])
						})
						var {width, height, size, maxWidth, maxHeight, radius} = sourceInfo
						// 最大值比较
						if (maxWidth > 10) {
							width = maxWidth
						} else if (maxWidth > 0) {
							if (height) {
								width = maxWidth * height
							}
						}
						if (maxHeight > 10) {
							height = maxHeight
						} else if (maxHeight > 0) {
							if (width) {
								height = maxHeight * width
							}
						}
						// 尺寸比较
						if (size > 0) {
							width = height = size
						}
						// 需要根据原图按比例来的类型
						var scaleType
						if (width && height) {
							// 有值就不管
						} else if (width || height) {
							// 无值，按照默认宽高比例来
							if (height) {
								scaleType = 'width'
								width = height * scale
							} else {
								scaleType = 'height'
								height = width / scale
							}
						} else {
							scaleType = 'height'
							// 默认宽度值180
							width = 180 || this.$root.RealWidth
							height = width / scale
						}
						// 到这里，一定有值
						this.sourceInfo.width = width
						this.sourceInfo.height = height
						this.sourceInfo.size = this.minValue([this.sourceInfo.width, this.sourceInfo.height])
						if (radius === -1) {
							this.borderRadius = this.sourceInfo.size * 0.5
						} else if (radius > 0) {
							this.borderRadius = radius
						}
						
						// 2，获取图片信息，拿到真实的宽高比例
						var iPath, srcList
						if (Array.isArray(src)) {
							if (src.length > 0) {
								if (bannerInfo) {
									srcList = src
								}
								iPath = src[0]
							}
						} else if (typeof(src) === 'string') {
							iPath = src
						}
						const getImageInfo = () => {
							if (iPath) {
								this.loading = 1
								const that = this
								uni.getImageInfo({
									src: iPath,
									success(res) {
										that.loading = 0
										imageSuccess(res, scaleType, srcList)
									},
									fail(error) {
										that.loading = 2
										console.warn(src)
										console.error(error)
									}
								})
							} else {
								this.loading = -2
								console.error(src)
								console.warn('图片路径不合法')
							}
						}
						if (iPath && iPath.indexOf(';base64,') > -1) { // 微信小程序不能直接使用base64的图片，通过该方法转换
							// baase64文件
							const buffer = uni.base64ToArrayBuffer(iPath.split(',')[1])
							const fs = uni.getFileSystemManager()
							const filePath = `${uni.env.USER_DATA_PATH}/temp_${Date.now() + parseInt(Math.random() * 100)}_image.png`
							fs.writeFile({
							    filePath,
							    data: buffer,
							    success: (res) => {
									iPath = filePath
									getImageInfo()
							    },
							    fail: (err) => {
									this.loading = -2
									console.warn(src)
									console.error(err)
									console.warn('图片转换错误')
							    }
							})
						} else {
							getImageInfo()
						}
					} else {
						this.loading = -2
						console.warn('没有图片路径')
					}
				}
			},
			
			// 图片获取成功。进一步处理尺寸
			imageSuccess(res, scaleType, srcList) {
				/**
				 * width, height: 返回图片都得宽高
				 * path: 返回图片的本地路径
				 * 下面两个，H5上没有
				 * orientation: 返回图片的方向
				 * type: 返回图片的格式
				 */
				this.iPath = res.path
				/**
				 * 无论如何都要保证不变形。保证同比放大和缩小
				 * 如果传入的width或者height，其中一个有值，则另一个将根据原图的比例来缩放
				 * 如果都有值或者都没有值，则先缩放宽度再缩放高度
				 */
				this.realInfo = {width: 0, height: 0}
				const {side, frame, newImage, colors, radius, sourceInfo, realInfo, intact} = this
				if (scaleType) {
					// 先修正sourceInfo
					if (scaleType === 'width') {
						sourceInfo.width = sourceInfo.height * res.width / res.height
					} else {
						sourceInfo.height = sourceInfo.width * res.height / res.width
					}
					sourceInfo.size = this.minValue([sourceInfo.width, sourceInfo.height])
				}
				// 先将宽度缩放到sourceInfo.width
				var wScale = sourceInfo.width / res.width, hScale
				realInfo.height = res.height * wScale
				realInfo.width = sourceInfo.width
				// 再降高度缩放到sourceInfo.height
				if (realInfo.height > sourceInfo.height) {
					hScale = sourceInfo.height / realInfo.height
					realInfo.width *= hScale
					realInfo.height = sourceInfo.height
				}
				// 再处理尺寸值和圆角
				realInfo.size = this.minValue([realInfo.width, realInfo.height])
				if (radius === -1) {
					this.borderRadius = realInfo.size * 0.5
				} else if (radius > 0) {
					this.borderRadius = radius
				}
				wScale = realInfo.width / res.width
				this.wScale = wScale
				hScale = realInfo.height / res.height
				this.hScale = hScale
				this.$emit('success', {...realInfo, wScale, hScale})
				if (side || frame || newImage || (colors && colors.length > 0)) {
					this.showCanvas = true
					// 数值或者百分数的转换。都相对于图片原始宽高来计算
					const valueFromImage = (value, type) => {
						if (typeof(value) === 'string') {
							if (value.substr(-1) === '%') {
								value = parseFloat(value.substr(0, value.length - 1))
								value = value * res[type] * 0.01
							} else {
								value = parseFloat(value) || 0
							}
						}
						if (value > res[type] * 0.5) {
							return res[type] * 0.5
						}
						return value
					}
					if (frame) {
						frame.x = valueFromImage(frame.x, 'width')
						frame.y = valueFromImage(frame.y, 'height')
						frame.width = valueFromImage(frame.width, 'width')
						frame.height = valueFromImage(frame.height, 'height')
					} else if (side) {
						if (typeof(side) === 'object') {
							intact.top = valueFromImage(side.top, 'height')
							intact.bottom = valueFromImage(side.bottom, 'height')
							intact.left = valueFromImage(side.left, 'width')
							intact.right = valueFromImage(side.right, 'width')
						} else {
							intact.top = valueFromImage(side, 'height')
							intact.bottom = valueFromImage(side, 'height')
							intact.left = valueFromImage(side, 'width')
							intact.right = valueFromImage(side, 'width')
						}
						this.initialMaterial(res)
					}
				} else {
					this.srcList = srcList
					this.showImage = true
				}
			},
			
			// 将尺寸对象变为style
			getSizeStyle(obj, borderRadius = true) {
				const style = {
					width: obj.width + 'px',
					height: obj.height + 'px',
				}
				if (borderRadius) {
					style.borderRadius = this.borderRadius + 'px'
				}
				return style
			},
			
			// 每部分完成后的方法
			drawComplete(imgUrl, item) {
				if (imgUrl && item) {
					item.src = imgUrl
					if (item.key === 'center') {
						// 回调中间部分
						const {wScale, hScale} = this
						this.$emit('center', item, {wScale, hScale})
					}
				}
				
				this.intact.count ++
				if (this.intact.count < 9) {
					// 继续执行
				} else {
					// 执行完毕
					this.intact.show = true
					this.intact.count = 0
					this.refreshSize()
				}
			},
			
			// 绘图的动作
			drawAction(context, size, drawImage, callback, data, getTempImageUrl, instance) {
				const {iPath, frame, side, colors, wScale, hScale} = this
				if (drawImage) {
					drawImage(iPath).then(res => {
						if (side || frame || (colors && colors.length > 0)) {
							const action = () => {
								if (frame) {
									const {x = 0, y = 0, width = 100, height = 100} = frame || {}
									uni.canvasToTempFilePath({
										...data,
										x: x * wScale, y: y * hScale, 
										width: width * wScale, height: height * hScale,
										destWidth: size(width * wScale), destHeight: size(height * hScale),
										success: (res) => {
											this.drawSuccess(getTempImageUrl(res))
										},
										fail: (err) => {
											console.error(err)
										}
									}, instance)
								} else if (side) {
									// 分别只取对应的部分
									this.material.map(arr => {
										arr.map(item => {
											uni.canvasToTempFilePath({
												...data,
												x: item.frame.x * wScale, y: item.frame.y * hScale,
												width: item.frame.width * wScale, height: item.frame.height * hScale,
												destWidth: size(item.frame.width * wScale), destHeight: size(item.frame.height * hScale),
												success: (res) => {
													this.drawComplete(getTempImageUrl(res), item)
												},
												fail: (err) => {
													console.error(err)
													this.drawComplete()
												}
											}, instance)
										})
									})
								} else {
									// 颜色值替换
								}
							}
							// #ifdef MP-WEIXIN
							action()
							// #endif
							// #ifndef MP-WEIXIN
							context.draw(true, action)
							// #endif
						} else {
							callback && callback()
						}
					})
				} else {
					callback && callback()
				}
			},
			
			// 绘图完成
			drawSuccess(imgUrl) {
				this.tempFilePath = imgUrl
				this.$emit('newImage', imgUrl)
			},
			
			// 点击了轮播中的图片
			onBanner(current) {
				uni.previewImage(this.bigInfo || {
					current,
					urls: this.srcList
				})
			},
			
			// 点击事件
			click(e) {
				if (this.showBig) {
					uni.previewImage(this.bigInfo || {
						current: 0,
						urls: [this.tempFilePath || this.iPath]
					})
				} else {
					this.$emit('click', e)
				}
			},
			
			/**
			 * 以下六个方法是保护性拉伸，side存在时特有
			 * refreshSize
			 * initialMaterial
			 * imageCount
			 * getRepeat
			 * reviseStyle
			 * getContentPadding
			 */
			
			/**
			 * 保护性拉伸模式，尺寸变化刷新。该方法可外部调用
			 * H5会自动刷新，小程序需延迟执行刷新
			 * 可以通过中间部分的插槽传递的参数refresh的方法手动调用以执行refreshSize
			 * 如果中间插槽有margin须提前指定，margin无法被组件计算在宽高内
			 * 
			 * 在H5中可以不传observeSize而能够自动获取子组件的宽高的，但是在微信小程序上不行
			 * 对策：通过observeSize传递其值
			 * 
			 * 在微信小程序父组件若是更改了observeSize里面的宽高，并不是引起这里的值的改变
			 * 对策：一开始赋值undefined，等到执行了@center事件后，再给observeSize赋值，这里就能读取到值了
			 */
			refreshSize(size = this.observeSize) {
				const {top = 0, left = 0, bottom = 0, right = 0} = size || {}
				const {hScale, wScale, realInfo, material} = this
				const action = (width, height) => {
					width += left + right
					height += top + bottom
					const {frame} = material[1][1]
					if (frame.width * wScale < width) {
						// 中间列的宽度都更改
						realInfo.width += width - frame.width * wScale
						this.centerInfo.width = width
					}
					if (frame.height * hScale < height) {
						// 中间行的高度都更改
						realInfo.height += height - frame.height * hScale
						this.centerInfo.height = height
					}
				}
				if (size.width && size.height) {
					// 外界手动调用立即执行。一般有延迟请求数据再渲染的情况
					action(size.width, size.height)
				} else {
					// 本文件内自动获取。一般是直接写的
					this.core.delayAction(() => {
						/**
						 * 宽高须设为auto才能被子组件撑大。宽度可以，高度为什么却没有显示被撑大？
						 * 对策
						 * H5可以直接通过this.$refs.center[0].children[0].offsetWidth/offsetHeight获取
						 */
						// #ifdef H5
						const {offsetWidth, offsetHeight} = this.$refs.center[0].children[0]
						action(offsetWidth, offsetHeight)
						// #endif
						// #ifndef H5
						// 宽度会被撑大，但是高度没有。对应方案就是在size中传入
						this.core.component.query('#center', this).then(res => {
							if (res) {
								action(res.width, res.height)
							}
						})
						// #endif
					}, 100)
				}
			},
			
			// 保护性拉伸的九部分数据初始化
			initialMaterial(res) {
				const {material, intact: {top, right, bottom, left}} = this
				const {width, height} = res
				for (let i = 0; i < material.length; i++) {
					for (let j = 0; j < material[i].length; j++) {
						const item = material[i][j]
						const {frame} = item
						switch (i){
							case 0:
								switch (j){
									case 0: // 左上角
										frame.x = 0
										frame.y = 0
										frame.width = left
										frame.height = top
										break
									case 1: // 上边
										frame.x = left
										frame.y = 0
										frame.width = width - left - right
										frame.height = top
										break
									case 2: // 右上角
										frame.x = width - right
										frame.y = 0
										frame.width = right
										frame.height = top
										break
								}
								break
							case 1:
								switch (j){
									case 0: // 左边
										frame.x = 0
										frame.y = top
										frame.width = left
										frame.height = height - top - bottom
										break
									case 1: // 中心
										frame.x = left
										frame.y = top
										frame.width = width - left - right
										this.centerInfo.width = frame.width * this.wScale
										frame.height = height - top - bottom
										this.centerInfo.height = frame.height * this.hScale
										break
									case 2: // 右边
										frame.x = width - right
										frame.y = top
										frame.width = right
										frame.height = height - top - bottom
										break
								}
								break
							case 2:
								switch (j){
									case 0: // 左下角
										frame.x = 0
										frame.y = height - bottom
										frame.width = left
										frame.height = bottom
										break
									case 1: // 下边
										frame.x = left
										frame.y = height - bottom
										frame.width = width - left - right
										frame.height = bottom
										break
									case 2: // 右下角
										frame.x = width - right
										frame.y = height - bottom
										frame.width = right
										frame.height = bottom
										break
								}
								break
						}
					}
				}
			},
			
			// 获取当前需要几个图片
			imageCount(index, idx, item) {
				const {centerInfo: {width, height}, wScale, hScale} = this
				var wCount = 1, hCount = 1
				if (idx === 1) {
					if (width > item.frame.width * wScale) {
						wCount = parseInt(width / (item.frame.width * wScale)) + 1
					}
				}
				if (index === 1) {
					if (height > item.frame.height * hScale) {
						hCount = parseInt(height / (item.frame.height * hScale)) + 1
					}
				}
				if (index === 1 && idx === 1) {
					return wCount * hCount
				}
				if (index === 1) { // 只看高度
					return hCount
				}
				if (idx === 1) { // 只看宽度
					return wCount
				}
				return 1
			},
			
			// 获取平铺的重复属性
			getRepeat(index, idx) {
				if (index === 1 && idx === 1) {
					// 最中间图片可垂直重复
					return 'repeat-y'
				} else if (index === 1) {
					// 中间的两侧图片，一定垂直重复
					return 'repeat-y'
				} else if (idx === 1) {
					// 中间的上下图片，一定是水平重复
					return 'repeat-x'
				}
				// 四个角一定不重复
				return 'no-repeat'
			},
			
			// 获取修正值样式
			reviseStyle(position) {
				const style = {}
				if (position === 'center') {
					
				} else {
					const arr = position.split(' ')
					arr.map(str => {
						style[`margin-${str}`] = revise * -1 + 'px'
					})
				}
				return style
			},
			
			/**
			 * 获取内容的间距
			 * 由于监听的尺寸无法获取最顶和最底的marginTop和marginBottom，所以需要通过observeSize插队过来变成padding
			 */
			getContentPadding() {
				const {top = 0, right = 0, bottom = 0, left = 0} = this.observeSize || {}
				return `${top}px ${right}px ${bottom}px ${left}px`
			},
		}
	}
</script>

<style>
	uni-image {
		display:inline-block;
	}
	
	image {
		display: block;
	}
</style>